package cn.foolishbird.crow.core.util;

import cn.foolishbird.crow.core.Cash;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * BeanUtils 转换工具
 *
 * @author  foolish-bird
 */
public final class BeanUtils {

    /**
     * 日志log
     */
    private static final Logger log = LoggerFactory.getLogger(BeanUtils.class);

    /**
     * bean获取方法前缀
     */
    public static final List<String> GET_PREFIX = Lists.newArrayList("get", "is");

    /**
     * 排除方法名
     */
    public static final Set<String> EXCLUDE_METHOD = Sets.newHashSet("getClass");

    private BeanUtils() {

    }

    /**
     * bean转换成treeMap
     *
     * @param bean
     * @return
     */
    public static Map<String, Object> beanToTreeMap(Object bean) {
        if (Objects.isNull(bean)) {
            throw new IllegalArgumentException("核心参数不能为空");
        }
        Map<String, Object> map = new HashMap<>();
        doBeanToTreeMap(bean, bean.getClass(), map);
        return map;
    }

    /**
     * bean转换成treeMap
     *
     * @param bean
     * @return
     */
    public static void beanToTreeMap(Object bean, Map<String, Object> treeMap) {
        if (Objects.isNull(bean) || Objects.isNull(treeMap)) {
            throw new IllegalArgumentException("核心参数不能为空");
        }
        doBeanToTreeMap(bean, bean.getClass(), treeMap);
    }

    /**
     * bean转换成treeMap
     * @param bean
     * @param clz
     * @param map
     */
    private static void doBeanToTreeMap(Object bean, Class<?> clz, Map<String, Object> map) {
        if (Objects.isNull(clz)) {
            return;
        }
        Method[] methods = clz.getDeclaredMethods();
        if (ArrayUtils.isEmpty(methods)) {
            return;
        }
        Arrays.stream(methods).filter(BeanUtils::beanMethod).forEach(m -> {
            try {
                map.put(beanKey(m), m.invoke(bean));
            } catch (IllegalAccessException |InvocationTargetException e ) {
                log.error("bean调用method方法失败:{}", e);
                throw new RuntimeException("bean调用method方法失败");
            }
        });

        if (!bean.getClass().getSuperclass().equals(Object.class)) {
            doBeanToTreeMap(bean, clz.getSuperclass(), map);
        }
    }

    /**
     * 是否是bean方法
     * @param method
     * @return
     */
    private static boolean beanMethod(Method method) {
       return GET_PREFIX.stream().filter(o -> method.getName().startsWith(o)).findAny().isPresent() &&
               !EXCLUDE_METHOD.contains(method.getName());
    }

    /**
     * 获取bean的前缀
     * @param method
     * @return
     */
    private static String beanKey(Method method) {
        String prefix =  GET_PREFIX.stream().filter(o -> method.getName().startsWith(o)).findFirst().get();
        if (prefix.length() >= method.getName().length()) {
            throw new RuntimeException("方法名不能是get/is");
        }
        String name = method.getName().substring(prefix.length());
        return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, name);
    }

}
